//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#if (_TEST_TYPE == 5)    /* Test for interrupt latency performance */ \
    || (_TEST_TYPE == 6) /* Test for interrupt dispatch latency performance */

#include <bsp.h>
//#include <cpu.h>

#include <ddk.h>
#include <stdio.h>
#include <serialio.h>

void TechfaithReboot();

EXTERN_C void CDECL TechReboot()
{
    while (TRUE) {
        TechfaithReboot();
    }
}

void Delay()
{
    DzDelay(100 * 1000);
}

static IDeviceDriver *g_pSerialDriver;

//#define _MULTIMEDIA_PDA

typedef struct tapitime_tag {
    UInt16 wYear;
    UInt16 wMonth;
    UInt16 wDay;
    UInt16 wHour;
    UInt16 wMinute;
    UInt16 wSecond;
} TAPITIME, *LPTAPITIME;

Boolean WriteSerial(void *pBuf, UInt32 uBufSize)
{
    UInt32 SizeWritten = 0;
    MemoryBuf ebData((Byte *)pBuf, uBufSize, uBufSize);

    ECode ec = g_pSerialDriver->Write(0, ebData, &SizeWritten, NULL);
    if (ec == NOERROR) {
        Delay();
        return TRUE;
    }

    kprintf("ERROR: Serial Write failed ec: 0x%08x\n", ec);
    return FALSE;
}

Boolean IsSleeping()
{
    unsigned int modem_states;
    MemoryBuf eaData((Byte *)&modem_states, sizeof(modem_states));

    // detect DSR
    g_pSerialDriver->Control(
        SERIALCONTROL_GETCONFIG | IO_GET_CONFIG_SERIAL_MODEM_STATUS,
        NULL_MEMORYBUF,
        &eaData,
        NULL);

    Delay();
    return ((modem_states & NUM_DSR_ON) == 0);
}

Boolean WakeUp(SERIAL_INFO *info)
{
    int times = 0;

    while (IsSleeping() && times++ < 10) {
        MemoryBuf ezData((Byte *)info, sizeof(*info));

        // set serial info
        info->flags &= ~NUM_SERIAL_FLOW_DSRDTR_RX;
        g_pSerialDriver->Control(
            SERIALCONTROL_SETCONFIG | IO_SET_CONFIG_SERIAL_INFO,
            ezData,
            NULL,
            NULL);
        Delay();

        info->flags |= NUM_SERIAL_FLOW_DSRDTR_RX;
        g_pSerialDriver->Control(
            SERIALCONTROL_SETCONFIG | IO_SET_CONFIG_SERIAL_INFO,
            ezData,
            NULL,
            NULL);
        Delay();

        if (!IsSleeping()) {
            return TRUE;
        }
    }

    if (times == 10) {
        return FALSE;
    }

    return TRUE;
}

void GetSerialInfo(SERIAL_INFO &info)
{
#ifdef _MULTIMEDIA_PDA
    info.baud = NUM_SERIAL_BAUD_115200;
    info.stop = NUM_SERIAL_STOP_1;
    info.parity = NUM_SERIAL_PARITY_NONE;
#else
    info.baud = NUM_SERIAL_BAUD_57600;
    info.stop = NUM_SERIAL_STOP_2;
    info.parity = NUM_SERIAL_PARITY_ODD;
#endif //_MULTIMEDIA_PDA

    info.word_length = NUM_SERIAL_WORD_LENGTH_8;
    info.flags =
        NUM_SERIAL_FLOW_RTSCTS_RX | NUM_SERIAL_FLOW_RTSCTS_TX |
        NUM_SERIAL_FLOW_DSRDTR_RX | NUM_SERIAL_FLOW_DSRDTR_TX;
}

Boolean ClearOutInBuf()
{
    ECode ec;
    // clean out-buffer & in-buffer
    ec = g_pSerialDriver->Control(
        SERIALCONTROL_GETCONFIG | IO_GET_CONFIG_SERIAL_OUTPUT_FLUSH,
        NULL_MEMORYBUF,
        NULL,
        NULL);
    if (ec != NOERROR) {
        return FALSE;
    }
    Delay();

    ec = g_pSerialDriver->Control(
        SERIALCONTROL_GETCONFIG | IO_GET_CONFIG_SERIAL_INPUT_FLUSH,
        NULL_MEMORYBUF,
        NULL,
        NULL);
    if (ec != NOERROR) {
        return FALSE;
    }
    Delay();

    return TRUE;
}

int InitSerial()
{
    ECode ec = DzFindService(L"device:serial1", (IInterface **)&g_pSerialDriver);
    if (FAILED(ec)) {
        kprintf("ERROR: Failed to find device:serial1.\n");
        return 1;
    }

    SERIAL_INFO SerialInfo;

    // set serial config info
    GetSerialInfo(SerialInfo);
    MemoryBuf ebcfgData((Byte *)&SerialInfo, sizeof(SerialInfo));
    ec = g_pSerialDriver->Control(
        SERIALCONTROL_SETCONFIG | IO_SET_CONFIG_SERIAL_INFO,
        ebcfgData,
        NULL,
        NULL);

    if (ec != NOERROR) {
        kprintf("ERROR: Failed to set serial config info.\n");
        return 1;
    }

    Delay();

    if (!ClearOutInBuf()) {
        kprintf("ERROR: ClearOutInBuf failed.\n");
        return 1;
    }

    if (!WakeUp(&SerialInfo)) {
        kprintf("ERROR: WakeUp time out.\n");
        return 1;
    }

    return 0;
}

int SetTime(TAPITIME *time)
{
    char tmpbuf[128];

    sprintf(
        tmpbuf,
        "AT+CCLK=\"%02d/%02d/%02d,%02d:%02d:%02d\"\x0D",
        time->wYear, time->wMonth, time->wDay,
        time->wHour, time->wMinute, time->wSecond);

    WriteSerial(tmpbuf, strlen(tmpbuf));
    //kprintf("Send: %s\n", tmpbuf);

    return 0;
}

int SetAlarm(TAPITIME *time)
{
    char tmpbuf[128];

    sprintf(
        tmpbuf,
        "AT+CALA=\"%02d/%02d/%02d,%02d:%02d:%02d\"\x0D",
        time->wYear, time->wMonth, time->wDay,
        time->wHour, time->wMinute, time->wSecond);

    WriteSerial(tmpbuf, strlen(tmpbuf));
    //kprintf("Send: %s\n", tmpbuf);

    return 0;
}

int ShutDown()
{
    char *tmpbuf = "AT+CPOF\x0D";

    WriteSerial(tmpbuf, strlen(tmpbuf));
    //kprintf("Send: %s\n", tmpbuf);

    return 0;
}

void InitTime(TAPITIME *time)
{
    time->wYear = 06;
    time->wMonth = 1;
    time->wDay = 1;
    time->wHour = 1;
    time->wMinute = 1;
    time->wSecond = 1;
}

void TechfaithReboot()
{
    InitSerial();

    TAPITIME time;
    InitTime(&time);

    SetTime(&time);

    //reboot after 1 minute shut down
    time.wMinute++;

    SetAlarm(&time);
    ShutDown();

    DzDelay(3000 * 1000);
}

#endif // _TEST_TYPE == 5 || _TEST_TYPE == 6
